/*+***********************************************************************************
 Filename: A01_tinyriscv_mcu01\src\peripheral.v
 Description: a module to hold all kinds of peripherals.

 Modification:
   2022.11.07 Creation   H.Zheng (03_tinycore_step04\src\peripheral.v)
   2024.01.07 change addr to 12 bit width
   2024.02.08 add timer, add int_flag output port, clk_1MHz input port
              change peripheral unit address space to 16 
Copyright (C) 2022  Zheng Hui (hzheng@gzhu.edu.cn)

License: MulanPSL-2.0

***********************************************************************************-*/

module peripheral (
    //from top
    input wire clk,
    input wire clk_1MHz,
    input wire reset_n,
    input wire button,
    output wire [5:0] led,
    input wire rxd,
    output wire txd,
    //from core
    input wire ce, //chip enable
    input wire wre, //write enable
    input wire [11:0] addr, //address bus
    input wire [31:0] data_in,
    output wire [31:0] data_out,
    output wire [7:0] int_flag
);
    //gpio
    //
    wire gpio_ce = (ce & (addr[11:4] == 8'h0)) ? 1'b1 : 1'b0;

    wire [31:0] gpio_data_out;
    gpio m_gpio(
        .clk(clk),
        .reset_n(reset_n),
        .button(button),
        .led(led),
        .ce(gpio_ce),
        .wre(wre),
        .addr(addr[3:0]),
        .data_in(data_in),
        .data_out(gpio_data_out)

    );

    //uart
    //
    wire uart0_ce = (ce & (addr[11:4] == 8'h1)) ? 1'b1 : 1'b0;

    wire [31:0] uart0_data_out;

    peripheral_uart m_uart0(
        .clk(clk),
        .reset_n(reset_n),
        .rxd(rxd),
        .txd(txd),
        .ce(uart0_ce),
        .wre(wre),
        .addr(addr[3:0]),
        .data_in(data_in),
        .data_out(uart0_data_out)
    );

    //timer
    wire timer0_ce = (ce & (addr[11:4] == 8'h2)) ? 1'b1 : 1'b0;
    wire [31:0] timer0_data_out;
    wire timer0_int;
    
    timer m_timer0(
        .clk(clk),
        .reset_n(reset_n),
        .data_i(data_in),
        .addr_i(addr[3:0]),
        .we_i(timer0_ce & wre),
        .data_o(timer0_data_out),
        .int_sig_o(timer0_int)
    );
    //data out mux
    assign data_out = (gpio_ce) ? gpio_data_out :
                      (uart0_ce) ? uart0_data_out :
                      (timer0_ce) ? timer0_data_out : 32'bz;

    //int flag
    assign int_flag ={7'b0, timer0_int};
    
endmodule
